#!/bin/bash

# 文档： http://tapd.oa.com/cmongo/markdown_wikis/#1010115521009348229

NAME_PREFIX=${NAME_PREFIX:-cmongo}
CMONGO_NET=${CMONGO_NET:-$NAME_PREFIX-net}
CMONGO_SUBNET=${CMONGO_SUBNET:-172.30.0.0}
LOG_LEVEL=${LOG_LEVEL:-debug}
LOG_STDOUT=${LOG_STDOUT:-0}

############ 为了避免与包管理器交互，这些版本binary全放在worker镜像的base镜像中，若以后需要增添其它版本，参考docker/Dockerfile-mongo即可
PROXY_VER_3_2=proxy2_mongos-v314
MONGO_VER_3_2=mongo_wt-v313

PROXY_VER_3_6=mongos3.6-v24
MONGO_VER_3_6=mongo_wt3.6-v35

PROXY_VER_4_0=mongos4.0-v55
MONGO_VER_4_0=mongo_wt4.0-v60

# 用以内核feature功能验证，worker镜像构建时将二进制打包进各个目录内
PROXY_VER_3_6_DEBUG=mongos3.6-test
MONGO_VER_3_6_DEBUG=mongo_wt3.6-test
PROXY_VER_4_0_DEBUG=mongos4.0-test
MONGO_VER_4_0_DEBUG=mongo_wt4.0-test


DEFAULT_PROXY_VER=$PROXY_VER_3_2
DEFAULT_MONGO_VER=$MONGO_VER_3_2

DEFAULT_CLUSTER=${NAME_PREFIX}-cluster-3.2

master_cov_pkg="git.code.oa.com/cmongo/cmongo/..."
worker_cov_pkg="git.code.oa.com/cmongo/cmongo/..."
monitor_cov_pkg="git.code.oa.com/cmongo/cmongo/..."
utils_cov_pkg="git.code.oa.com/cmongo/cmongo/utils"

integration_cov_pkg="git.code.oa.com/cmongo/cmongo/..."

master_cov_file=cov.master
worker_cov_file=cov.worker
monitor_cov_file=cov.monitor
utils_cov_file=cov.utils
cov_profile_file=cov.out

integration_cov_file=cov.integration

root_user_salt=`cat utils/salt_string.go | grep 'ROOT_USER_SALT' | sed 's/"//g' | awk -F ' ' '{ print $3 }'`
md5_salt=`cat utils/salt_string.go | grep 'MD5_SALT' | sed 's/"//g' | awk -F ' ' '{ print $3 }'`
salt_string=$root_user_salt-$md5_salt

if [ $# -lt 1 ]; then
    echo "sub command not given"
    exit 1
fi

install_docker_compose() {
    echo "installing docker compose ..."
    curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

    chmod u+x /usr/local/bin/docker-compose
}

echo_with_color() {
    echo -e "\033[34m$1\033[0m"
}

install_salt_string() {
    pwd
    ls -l salt_string
    cp salt_string/salt_string.go utils/
    rm -rf salt_string
    ls -l utils
}

check_env() {
    echo "################# checking orange-ci runner env:"
    pwd
    ls -a
    echo "################# current branch: "
    git branch
    git log --oneline -10
    ip a
    docker version
    echo "################# curl testing ..."
    curl -s --connect-timeout 3 www.baidu.com
    curl -s --connect-timeout 5 http://omc-ossdb.oa.com
    git --version
    env
    go env
    echo "DOCKER_CMONGO_PREFIX=$DOCKER_CMONGO_PREFIX"
}

# 这个函数适合于在连mongos前执行一次，以便不同的角色连接各自对应的mongos
set_mongos_ip() {
    case $NAME_PREFIX in
    cmongo)
        IP_MARKER=30
        mongos_ip=172.30.0.16
        ;;
    cshi)
        IP_MARKER=31
        mongos_ip=172.31.0.16
        ;;
    demon)
        IP_MARKER=32
        mongos_ip=172.32.0.16
        ;;
    zy)
        IP_MARKER=33
        mongos_ip=172.33.0.16
        ;;
    phe)
        IP_MARKER=34
        mongos_ip=172.34.0.16
        ;;
    walker)
        IP_MARKER=35
        mongos_ip=172.35.0.16
        ;;
    *)
        echo_with_color "invalid name prefix: $NAME_PREFIX"
        exit 1
        ;;
    esac
}

export_env() {
    case $NAME_PREFIX in
    cshi)
        IP_MARKER=31
        ;;
    demon)
        IP_MARKER=32
        ;;
    zy)
        IP_MARKER=33
        ;;
    phe)
        IP_MARKER=34
        ;;
    walker)
        IP_MARKER=35
        ;;
    *)
        echo_with_color "invalid name prefix: $NAME_PREFIX"
        exit 1
        ;;
    esac
    echo_with_color "Please copy and set them on the current commandline"

    env_vars_for_local_testing="export ETCD_HOST=172.${IP_MARKER}.0.13 MASTER_HOST=172.${IP_MARKER}.0.14 MONITOR_HOST=172.${IP_MARKER}.0.15 WORKER_HOSTS=\"172.${IP_MARKER}.0.16 172.${IP_MARKER}.0.17 172.${IP_MARKER}.0.18 172.${IP_MARKER}.0.19 172.${IP_MARKER}.0.20 172.${IP_MARKER}.0.21 172.${IP_MARKER}.0.22 172.${IP_MARKER}.0.23 172.${IP_MARKER}.0.24 172.${IP_MARKER}.0.25 172.${IP_MARKER}.0.26 172.${IP_MARKER}.0.27\" OSS_IMAGE_TAG=${NAME_PREFIX}-test-tag DOCKER_ETCD_URL=docker.oa.com/library/etcd:2.2.5-service DOCKER_CMONGO_PREFIX=docker.oa.com/cmongo CMONGO_NET=${NAME_PREFIX}-net LOG_LEVEL=debug LOG_STDOUT=0 CMONGO_SUBNET=172.${IP_MARKER}.0.0"
    echo $env_vars_for_local_testing > env-vars-for-local-testing
    echo $env_vars_for_local_testing
}

print_component_coverage() {
    echo_with_color "printing $1 coverage ..."
    tail $1.func | tail -1 | awk '{print $3}'
}
# must execute go tool cover first to generate the func file
count_overall_coverage() {
    print_component_coverage $master_cov_file
    print_component_coverage $worker_cov_file
    print_component_coverage $monitor_cov_file
    print_component_coverage $utils_cov_file
    print_component_coverage $integration_cov_file

    echo "mode: set" > $cov_profile_file
    grep -v '^mode:' $master_cov_file >> $cov_profile_file
    grep -v '^mode:' $worker_cov_file >> $cov_profile_file
    grep -v '^mode:' $monitor_cov_file >> $cov_profile_file
    grep -v '^mode:' $utils_cov_file >> $cov_profile_file
    grep -v '^mode:' $integration_cov_file >> $cov_profile_file
}

module=$1

case $module in
install-salt-string)
    install_salt_string
    ;;
check-env)
    check_env
    ;;
create-env|ce)
    # just for testing
    export_env
    ;;

create-net)
    echo_with_color "CMONGO_NET=$CMONGO_NET"
    if docker network ls | grep "$CMONGO_NET"; then
        docker network rm $CMONGO_NET
    fi
    docker network create --subnet $CMONGO_SUBNET/16 $CMONGO_NET
    ;;
build|b)
    docker run --rm -v $PWD:/cmongo $DOCKER_CMONGO_PREFIX/cmongo-build bash -c "cd /cmongo-build/src/git.code.oa.com/cmongo/cmongo; bash build.sh master worker monitor mastertest maintenance"
    ;;
buildimage|bi)
    docker build -f docker/Dockerfile-master -t $DOCKER_CMONGO_PREFIX/master:$OSS_IMAGE_TAG .
    docker build -f docker/Dockerfile-monitor -t $DOCKER_CMONGO_PREFIX/monitor:$OSS_IMAGE_TAG .
    docker build -f docker/Dockerfile-worker -t $DOCKER_CMONGO_PREFIX/worker:$OSS_IMAGE_TAG .
    ;;
etcd|et)
    docker run --rm -d --network=$CMONGO_NET --ip=$ETCD_HOST --name etcd-$ETCD_HOST $DOCKER_ETCD_URL etcd \
        --name etcd -initial-advertise-peer-urls http://$ETCD_HOST:2380 -listen-peer-urls http://$ETCD_HOST:2380 \
        -listen-client-urls http://$ETCD_HOST:2379 -advertise-client-urls http://$ETCD_HOST:2379 \
        --data-dir ./data -initial-cluster etcd=http://$ETCD_HOST:2380
    sleep 5
    # avoiding monitor startup error
    docker exec etcd-$ETCD_HOST etcdctl --endpoint=http://$ETCD_HOST:2379 mkdir /cluster
    docker exec etcd-$ETCD_HOST etcdctl --endpoint=http://$ETCD_HOST:2379 ls
    ;;
master|ma)
    # 传 DOCKER_CMONGO_PREFIX 是为了忽略 某些外部系统如包管理、cmdb
    docker run --rm -d -v $PWD/log.master:/log --network=$CMONGO_NET --ip=$MASTER_HOST \
        -e ETCD_HOST=$ETCD_HOST -e MASTER_HOST=$MASTER_HOST -e LOG_LEVEL=$LOG_LEVEL -e LOG_STDOUT=$LOG_STDOUT \
        -e DOCKER_CMONGO_PREFIX=$DOCKER_CMONGO_PREFIX \
        --name master-$MASTER_HOST $DOCKER_CMONGO_PREFIX/master:$OSS_IMAGE_TAG
    sleep 3
    # check connectivity between client and master/etcd
    docker exec master-$MASTER_HOST bin/mastertest \
        -etcd=http://$ETCD_HOST:2379 -master_address=$MASTER_HOST:8888 -cmd ping -c 3

    ;;
monitor|mo)
    docker run --rm -d -e ETCD_HOST=$ETCD_HOST --network=$CMONGO_NET --ip=$MONITOR_HOST \
        -e MONITOR_HOST=$MONITOR_HOST -e LOG_LEVEL=$LOG_LEVEL -v $PWD/log.monitor:/log -e LOG_STDOUT=$LOG_STDOUT \
        -e DOCKER_CMONGO_PREFIX=$DOCKER_CMONGO_PREFIX \
        --name monitor-$MONITOR_HOST $DOCKER_CMONGO_PREFIX/monitor:$OSS_IMAGE_TAG
    ;;
worker|w)
    for h in $WORKER_HOSTS; do
        echo_with_color "docker run worker: $h"
        # make cgroup writable
        docker run --rm -d --privileged --network=$CMONGO_NET --ip=$h --name worker-$h \
            -e WORKER_HOST=$h -e LOG_LEVEL=$LOG_LEVEL -e LOG_STDOUT=$LOG_STDOUT \
            -e DOCKER_CMONGO_PREFIX=$DOCKER_CMONGO_PREFIX \
            -v $PWD/log.$h:/log -v $PWD/data.$h:/workdata \
            $DOCKER_CMONGO_PREFIX/worker:$OSS_IMAGE_TAG
    done
    ;;
log|l)
    if [ $2 = master -o $2 = ma ]; then
        echo_with_color "master log:"
        if [ $LOG_STDOUT = 1 ]; then
            docker logs master-$MASTER_HOST
        else
            tail log.master/master.log
        fi
    elif [ $2 = monitor -o $2 = mo ]; then
        echo_with_color "monitor log:"
        if [ $LOG_STDOUT = 1 ]; then
            docker logs monitor-$MONITOR_HOST
        else
            tail log.monitor/monitor.log
        fi
    elif [ $2 = worker -o $2 = w ]; then
        for h in $WORKER_HOSTS; do
            echo_with_color "tailing $h worker.log ..."
            if [ $LOG_STDOUT = 1 ]; then
                docker logs worker-$h
            else
                tail log.$h/worker.log
            fi
        done
    fi
    ;;

error|err)
    if [ $2 = master -o $2 = ma ]; then
        echo_with_color "############### master log:"
        if [ $LOG_STDOUT = 1 ]; then
            # if no error log, ignore return value ($?)
            docker logs master-$MASTER_HOST | grep -i '\[err' || echo
        else
            echo "====== master.log* ..."
            grep -H -i '\[err' log.master/master.log* || echo
            echo "====== master1.log* ..."
            grep -H -i '\[err' log.master/master1.log* || echo
        fi
        # 查看nohup 文件以捕捉可能的错误
        if [ -e "log.master/master.nohup" ]; then
            grep -C 10 'nil' log.master/master.nohup || echo
        fi
    elif [ $2 = monitor -o $2 = mo ]; then
        echo_with_color "############### monitor log:"
        if [ $LOG_STDOUT = 1 ]; then
            docker logs monitor-$MONITOR_HOST | grep -i '\[err' || echo
        else
            cat log.monitor/monitor.log | grep -i '\[err' || echo
        fi
    elif [ $2 = worker -o $2 = w ]; then
        for h in $WORKER_HOSTS; do
            echo_with_color "############### tailing $h worker.log ..."
            ls -lh log.$h
            if [ $LOG_STDOUT = 1 ]; then
                docker logs worker-$h | grep -i '\[err' || echo
            else
                echo "====== worker1.log ..."
                grep -H -i '\[err' log.$h/worker1.log* || echo
                echo "====== worker.log ..."
                grep -H -i '\[err' log.$h/worker.log* || echo
            fi
            if [ -e "log.$h/worker.nohup" ]; then
                grep -C 10 'nil' log.$h/worker.nohup || echo
            fi
        done
    fi
    ;;

start)
    # for manual testing
    bash $0 etcd &&
    bash $0 master &&
    bash $0 monitor &&
    bash $0 worker &&
    docker ps
    ;;
run)
    echo_with_color "start oss, create 3.2, 3.6, 4.0 clusters (two for each kind) ..."
    start=$(date +%s)
    # for manual testing
    bash $0 start &&
    bash $0 pro   &&
    bash $0 cc    &&
    bash $0 write 3.2 6000 &&
    bash $0 cc 3.6         &&
    bash $0 write 3.6 6001 &&
    bash $0 cc 4.0         &&
    bash $0 write 4.0 6002 &&
    bash $0 stats 3.2 &&
    bash $0 stats 3.6 &&
    bash $0 stats 4.0 &&

    # 它们的mongos端口分别是 6003, 6004, 6005 (3.2, 3.6, 4.0的 2nd 集群主要为了测试双集群的相关功能如同步、备份)
    bash $0 cc 3.2 2nd &&
    bash $0 cc 3.6 2nd &&
    bash $0 cc 4.0 2nd &&

    end=$(date +%s)
    echo_with_color "done, took $((end-start))s"
    ;;

stop)
    docker stop etcd-$ETCD_HOST
    docker stop master-$MASTER_HOST
    docker stop monitor-$MONITOR_HOST
    for h in $WORKER_HOSTS; do
        docker stop worker-$h
    done
    sleep 5

    rm -rf data.172.* log.* || echo_with_color "you may need to delete data/log dir manually"
    # delete all stopped containers
    docker container prune -f
    ;;
provisioning|pro)  # 上架各种类型的机器
    i=0
    for h in $WORKER_HOSTS; do
        i=$((i+1))
        if [ $i -lt 4 ]; then
            # machine type(deploy): proxy
            echo_with_color "provisioning proxy host: $h"
            docker exec master-$MASTER_HOST bin/mastertest \
                -master_address=$MASTER_HOST:8888 -cmd add -region 1 -set 1 \
                -cpunum 2 -disk 600 -disknum 1 -memory 600 -deploy 3 -max_memory 500 -max_num 100 -idc_id 1 -rack_id 1 -ip $h
        elif [ $i -ge 4 -a $i -lt 7 ]; then
            # config server
            echo_with_color "provisioning configserver host: $h"
            docker exec master-$MASTER_HOST bin/mastertest \
                -master_address=$MASTER_HOST:8888 -cmd add -region 1 -set 1 -cpunum 2 \
                -disk 102400 -disknum 1 -memory 4096 -deploy 8 -max_memory 4096 -max_num 100 -idc_id 1 -rack_id 1 -ip $h
        else
            # machine type(deploy): only for docker， 这里的CPU只有 9核
            # 目的是为了让CI流程中创建的两个集群分布在不同的3台机器上
            # wt engine need quota memory > 2G
            # 并存的集群越多时，memory, max_memory给的也要越多，否则后来的集群会创建失败
            echo_with_color "provisioning mongod host: $h"
            docker exec master-$MASTER_HOST bin/mastertest \
                -master_address=$MASTER_HOST:8888 -cmd add -region 1 -set 1  \
                -deploy 100 -max_memory 12288 -max_num 100 -idc_id 1 -rack_id 1 -ip $h
        fi
    done
    ;;

unprovisioning|unpro)
    for h in $WORKER_HOSTS; do
        echo_with_color "unprovisioning host: $h"
        docker exec master-$MASTER_HOST bin/mastertest -master_address=$MASTER_HOST:8888 -cmd del -region 1 -set 1 -ip $h
    done
    ;;

create-cluster|cc)
    start=$(date +%s)
    proxy_ver=$DEFAULT_PROXY_VER
    mongo_ver=$DEFAULT_MONGO_VER
    mongo_ver_num=2
    cluster_type=0 # default replica set for 3.2
    if [ x$2 != x ]; then
        if [ x$2 = x3.6 ]; then
            cluster_type=1  # >=3.6 doesn't support RS
            proxy_ver=$PROXY_VER_3_6
            mongo_ver=$MONGO_VER_3_6
            mongo_ver_num=4 # 3.6 wt
            DEFAULT_CLUSTER=$NAME_PREFIX-cluster-3.6
        elif [ x$2 = x"3.6-debug" ]; then
            cluster_type=1
            proxy_ver=$PROXY_VER_3_6_DEBUG
            mongo_ver=$MONGO_VER_3_6_DEBUG
            mongo_ver_num=4 # 3.6 wt
            DEFAULT_CLUSTER=$NAME_PREFIX-cluster-3.6-debug
        elif [ x$2 = x"4.0" ]; then
            cluster_type=1  # >=3.6 doesn't support RS
            proxy_ver=$PROXY_VER_4_0
            mongo_ver=$MONGO_VER_4_0
            mongo_ver_num=5
            DEFAULT_CLUSTER=$NAME_PREFIX-cluster-4.0
        elif [ x$2 = x"4.0-debug" ]; then
            cluster_type=1
            proxy_ver=$PROXY_VER_4_0_DEBUG
            mongo_ver=$MONGO_VER_4_0_DEBUG
            mongo_ver_num=5
            DEFAULT_CLUSTER=$NAME_PREFIX-cluster-4.0-debug
        elif [ x$2 = x"3.2" ]; then
            :
        else
            echo_with_color "no such proxy/mongo version"
            exit 1
        fi

        if [ x$3 = x"2nd" ]; then
            # create the second cluster for corresponding mongo version, for use of sync, backup
            DEFAULT_CLUSTER=${DEFAULT_CLUSTER}_2
        fi
    fi

    # clear black_list first in case last cc fails and some hosts are then blacklisted
    # Not suitable for CI. Do it manully when necessary
    # docker exec $DOCKER_ETCD_URL etcdctl --endpoint=http://$ETCD_HOST:2379 rm --recursive /black_list

    echo_with_color "install cluster: proxy_ver=$proxy_ver, mongod_subver=$mongo_ver"

    # MachineType_ONLY_FOR_DOCKER
    # cpu,disk,memory are quotas, fraction of a host's total resource
    # if enabling cgroup, use `--privileged` for worker docker host to make /sys/fs/cgroup/ writable
    docker exec master-$MASTER_HOST bin/mastertest \
        -master_address=$MASTER_HOST:8888 -cmd create -region 1 -set 1 -cluster=$DEFAULT_CLUSTER \
        -cpunum=3 -disk=8192 -memory=2048 -cluster_ver=1 -cluster_type=$cluster_type -machine_type=100 -rs_num=1 \
        -mongo_ver=$mongo_ver_num -proxy_ver $proxy_ver -mongod_subver $mongo_ver -close_cgroup 1 \
        -vips 127.0.0.1:30000,127.0.0.1:30001,127.0.0.1:30002

    i=0
    ok=false
    while true; do
        docker exec etcd-$ETCD_HOST etcdctl --endpoint=http://$ETCD_HOST:2379 ls /cluster
        sleep 10
        echo "checking status flag at /cluster/$DEFAULT_CLUSTER ..."
        clusterinfo=`docker exec etcd-$ETCD_HOST etcdctl --endpoint=http://$ETCD_HOST:2379 get /cluster/$DEFAULT_CLUSTER`
        if echo "$clusterinfo" | grep '"status":1'; then
            ok=true
            # 保存一份在本地，方便查看
            echo "$clusterinfo" > log.master/$DEFAULT_CLUSTER.info
            break
        fi
        i=$((i+1))
        # 预估在OCI上创建任何一种集群的最大时间（偶然网络问题可能长了导致CI失败，rebuild，或者增大它）
        if [ $i = 20 ]; then break; fi
    done

    if [ $ok = true ]; then
        end=$(date +%s)
        echo_with_color "Cluster: $DEFAULT_CLUSTER created done, took $((end-start))s"
    else
        echo_with_color "Cluster: $DEFAULT_CLUSTER created failed"
        bash docker/oss-docker-run.sh error master
        bash docker/oss-docker-run.sh error worker
        exit 1
    fi

    # other optional settings
    # db.createUser({user:"mongo-admin",pwd:"admin",roles:[{ role: "userAdminAnyDatabase", db:"admin"}], mechanisms:["SCRAM-SHA-1"]})
    # db.createUser({user:"mongo-root",pwd:"admin",roles:[{ role: "root", db:"admin"}], mechanisms:["SCRAM-SHA-1"]})
    #  mongo mongodb://mongo-root:admin@localhost:27017/admin
    #  mongo mongodb://user1:user1@localhost:27017/db1
    #  db.createRole({role:"my", privileges:[ {resource: {db:"",collection:""}, actions:["find", "createIndex"] }], roles:[{role:"readAnyDatabase", db:"admin"}] })
    # 3.2 admin 查看system.users失败： Error: error: { "ok" : 0, "errmsg" : "not allowed to visit admin", "code" : 73 }
    # db.changeUserPassword("user1", "user11")
    ;;

stats)
    mongos_port=6000
    passwd=$NAME_PREFIX-cluster-3.2

    if [ x$2 = x"3.6" ]; then
        mongos_port=6001
        passwd=$NAME_PREFIX-cluster-3.6
    elif [ x$2 = x"4.0" ]; then
        mongos_port=6002
        passwd=$NAME_PREFIX-cluster-4.0
    fi
    if [ x$3 != x ]; then
        # 给了$3, 就一定要给个$2
        # in default situation, 6000 is for 3.2, 6001 for 3.6, 6002 for 4.0. But we can still change the default by $3
        mongos_port=$3
    fi
    if [ x$4 != x ]; then
        # 命令行可更改passwd，即cluster名称. 同理给了$4, $3, $2就都要给出
        passwd=$4
    fi

    docker exec etcd-$ETCD_HOST etcdctl --endpoint=http://$ETCD_HOST:2379 ls /cluster

    echo_with_color "getting $passwd info ..."
    cluster_info=$(docker exec etcd-$ETCD_HOST etcdctl --endpoint=http://$ETCD_HOST:2379 get /cluster/$passwd) # | python -m json.tool
    echo "$cluster_info"
    nodestr=$(echo "$cluster_info" | jq -r '.rs_list[0].mongod_list[].container_name')
    echo -e "mongod node:\n$nodestr"
    node_arr=($(echo $nodestr))  # mongod node array
    node1_container=${node_arr[0]}
    node1_endpoint=${node1_container%:*}

    set_mongos_ip

    echo_with_color "issuing isMaster/db.stats/getShardMap/... against $passwd ..."

    echo "CMD: mongo mongodb://$passwd:$passwd-$salt_string@$node1_endpoint/admin --eval \"JSON.stringify(db.isMaster())\""
    primary=$(docker exec worker-$mongos_ip mongo mongodb://$passwd:$passwd-$salt_string@$node1_endpoint/admin --eval "JSON.stringify(db.isMaster())" | sed '1,2d' | jq -r '.primary')
    echo "cluster: $passwd primary is $primary"
    docker exec worker-$mongos_ip mongo -u mongouser -p $passwd $mongos_ip:$mongos_port/admin --eval "db.stats()"
    docker exec worker-$mongos_ip mongo -u mongouser -p $passwd $mongos_ip:$mongos_port/admin --eval "db.runCommand({getShardMap:1})"

    # 也可以试试连mongod, config
    # 第一个集群的mongod 有3个ip， 端口都是7000, 第二个都是 7001 , 依次类推
    # 第一个集群的config server 有3个ip， 端口都是7000, 第二个都是 7001
    ;;

write)
    echo_with_color "feed some sample data into cluster ..."

    mongos_port=6000
    passwd=$NAME_PREFIX-cluster-3.2
    if [ x$2 = x"3.6" ]; then
        mongos_port=6001
        passwd=$NAME_PREFIX-cluster-3.6
    elif [ x$2 = x"4.0" ]; then
        mongos_port=6002
        passwd=$NAME_PREFIX-cluster-4.0
    fi
    if [ x$3 != x ]; then
        # in default situation, 6000 is for 3.2, 6001 for 3.6, 6002 for 4.0. But we can still change the default by $3
        mongos_port=$3
    fi

    set_mongos_ip

    # write some sample data

    cat << eof > ./prepare.js
    use db1
    for(var i=1; i<=100; i++) { db.t.insert({id:i, "value": i+1}); }
    use db2
    for(var i=1; i<=200; i++) { db.t.insert({id:i, "value": i+2}); }

    //use admin
    // 3.2 不支持mechanisms, 3.6、4.0又得给mechanisms
    //db.createUser({user:"user1", pwd:"user1", roles:[{role:"readWrite", db:"db1"}]})
    //db.createUser({user:"user1", pwd:"user1", roles:[{role:"readWrite", db:"db1"}], mechanisms:["SCRAM-SHA-1"] })
eof
   
    docker run --rm --network=$CMONGO_NET -v $PWD:/mnt docker.oa.com/cmongo/mongo \
        bash -c "cat /mnt/prepare.js | mongo mongodb://mongouser:$passwd@$mongos_ip:$mongos_port/admin?authSource=admin"
    ;;

unittest|ut)
    # FIXME: cmongo-build's WORKDIR is /cmongo-build !
    # cgroup test needs privileged
    # cannot run like this after adding coverage options
    #docker run --privileged --rm -v $PWD:/cmongo $DOCKER_CMONGO_PREFIX/cmongo-build bash -c "cd /cmongo-build/src/git.code.oa.com/cmongo/cmongo; go test -v ./master/... ./worker/... ./monitor/... ./utils/..."
    docker run --privileged --rm -v $PWD:/cmongo -e DOCKER_CMONGO_PREFIX=$DOCKER_CMONGO_PREFIX $DOCKER_CMONGO_PREFIX/cmongo-build bash -c "cd /cmongo-build/src/git.code.oa.com/cmongo/cmongo; go test -v -coverpkg "$master_cov_pkg" -coverprofile=$master_cov_file ./master/..."
    docker run --privileged --rm -v $PWD:/cmongo -e DOCKER_CMONGO_PREFIX=$DOCKER_CMONGO_PREFIX $DOCKER_CMONGO_PREFIX/cmongo-build bash -c "cd /cmongo-build/src/git.code.oa.com/cmongo/cmongo; go test -v -coverpkg "$worker_cov_pkg" -coverprofile=$worker_cov_file ./worker/..."
    docker run --privileged --rm -v $PWD:/cmongo -e DOCKER_CMONGO_PREFIX=$DOCKER_CMONGO_PREFIX $DOCKER_CMONGO_PREFIX/cmongo-build bash -c "cd /cmongo-build/src/git.code.oa.com/cmongo/cmongo; go test -v -coverpkg "$monitor_cov_pkg" -coverprofile=$monitor_cov_file ./monitor/..."
    docker run --privileged --rm -v $PWD:/cmongo -e DOCKER_CMONGO_PREFIX=$DOCKER_CMONGO_PREFIX $DOCKER_CMONGO_PREFIX/cmongo-build bash -c "cd /cmongo-build/src/git.code.oa.com/cmongo/cmongo; go test -v -coverpkg "$utils_cov_pkg" -coverprofile=$utils_cov_file ./utils/..."
    ;;

int-test|it)
    # 凡是需要给出cluster name的子命令，都需要有这一逻辑判断
    if [ x$2 != x ]; then
        if [ x$2 = x3.6 ]; then
            DEFAULT_CLUSTER=$NAME_PREFIX-cluster-3.6
        elif [ x$2 = x4.0 ]; then
            DEFAULT_CLUSTER=$NAME_PREFIX-cluster-4.0
        else
            echo_with_color "no such proxy/mongo version"
            exit 1
        fi
    fi

    integration_test_command="go test -v -coverpkg $integration_cov_pkg -coverprofile=$integration_cov_file ./cmd/mastertest/masterclient/... -master_address $MASTER_HOST:8888 -etcd=http://$ETCD_HOST:2379 -cluster $DEFAULT_CLUSTER"

    # FIXME: why go test -v ./cmd/mastertest/... not working ??
    docker run --privileged --network=$CMONGO_NET --rm -v $PWD:/cmongo $DOCKER_CMONGO_PREFIX/cmongo-build bash -c "cd /cmongo-build/src/git.code.oa.com/cmongo/cmongo; $integration_test_command"
    ;;

count-coverage)
    master_cov_command="go tool cover -func=$master_cov_file -o $master_cov_file.func"
    worker_cov_command="go tool cover -func=$worker_cov_file -o $worker_cov_file.func"
    monitor_cov_command="go tool cover -func=$monitor_cov_file -o $monitor_cov_file.func"
    utils_cov_command="go tool cover -func=$utils_cov_file -o $utils_cov_file.func"
    integration_cov_command="go tool cover -func=$integration_cov_file -o $integration_cov_file.func"

    # FIXME: HOW TO pass shell function to docker run ?
    docker run --rm -v $PWD:/cmongo $DOCKER_CMONGO_PREFIX/cmongo-build bash -c "$master_cov_command; $worker_cov_command; $monitor_cov_command; $utils_cov_command; $integration_cov_command"
    count_overall_coverage

    # after merging all coverage file, output overall coverate ratio
    docker run --rm -v $PWD:/cmongo $DOCKER_CMONGO_PREFIX/cmongo-build bash -c "go tool cover -func=$cov_profile_file | tail -1"
    ;;
env)
    # for local test, LOG_LEVEL=debug
    export ETCD_HOST=172.30.0.13 MASTER_HOST=172.30.0.14 MONITOR_HOST=172.30.0.15 WORKER_HOSTS="172.30.0.16 172.30.0.17 172.30.0.18 172.30.0.19 172.30.0.20 172.30.0.21" OSS_IMAGE_TAG=test-tag DOCKER_ETCD_URL=docker.oa.com/library/etcd:2.2.5-service DOCKER_CMONGO_PREFIX=docker.oa.com/cmongo CMONGO_NET=my-net LOG_LEVEL=debug LOG_STDOUT=0
    export DOCKER_ETCD_URL=docker.oa.com/library/etcd:2.2.5-service DOCKER_ETCD_NAME=etcd
    ;;
sleep)
    i=0
    while true; do
        i=$((i+1))
        echo "sleep 300s, i=$i"
        sleep 300
        if [ $i -gt 10 ]; then break; fi
    done
    ;;
help|h)
    echo_with_color "run order: create-env, create-net, build, buildimage, start, provisioning, create-cluster, stop"
    exit 0
    ;;

pytest)
    version=$2
    # worker has mongod & mastertest
    docker run --rm -v $PWD:/cmongo --network=$CMONGO_NET $DOCKER_CMONGO_PREFIX/worker:$OSS_IMAGE_TAG bash -c "cd /cmongo; python3 docker/oss-test.py $version"
    exit_code=$?
    if [ $exit_code != 0 ]; then
        # 如果出错，在OCI退出前，可以打印出错误日志
        echo_with_color "pytest $version failed"
        bash docker/oss-docker-run.sh error master
        bash docker/oss-docker-run.sh error worker
        exit $exit_code
    fi
    ;;

restart)
    # rebuild master and restart after some modifications iteratively
    bash docker/oss-docker-run.sh b &&
    docker build -f docker/Dockerfile-master -t $DOCKER_CMONGO_PREFIX/master:$OSS_IMAGE_TAG . &&
    docker stop master-$MASTER_HOST && sleep 8 &&
    bash docker/oss-docker-run.sh master

    ;;
oneliner)
    # delete none images
    docker rmi $(docker images -f dangling=true -q)
    ;;
*)
    echo "no such module: $module"
    exit 1
    ;;
esac
